1. 의존관계 주입이란?
사용
의존관계 주입(Dependency Injection), 의존관계 주입은 객체를 생성하고, 의존하는 객체를 직접 생성하지 않고, 생성된 객체를 주입하여 사용합니다.
Spring에서의 DI
- 생성자 주입
- Setter 주입
- 필드 주입
- 일반 메서드 주입
많은 방법들이 있지만 거의 생성자 주입 혹은 Setter 주입을 사용하게 됩니다.
2. DI 방법 및 예시
생성자 주입
- 생성자 호출 시점에 딱 한번만 호출된다.
- 무조건적으로 의존관계가 필요한 경우 사용하게 된다.
- 👺 생성자가 딱 한개만 있으면 @Autowired를 생략해도 자동주입된다.
- 예시
setter 주입
setter이라고 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 DI한다
- 선택, 변경할 수 있는 의존관계에 사용한다.
- 기존처럼 setter형식으로 사용하면 된다
- 예시
자바빈 프로퍼티
JAVA에는 과거부터 필드의 값을 직접적으로 만지지 않고 Getter, Setter라는 메서드를 통해서 값을 일거나 수정하는 규칙을 만들었다. 해당 내용이 자바 빈 프로퍼티이다.
필드 주입
말 그대로 필드에 직접적으로 주입하는 방법이다.
- 간단하지만 스프링 DI 프레임워크가 없으면 무용지물이다.
- 거의 사용하지 않는다
- 당연하게도 자바 빈 내부에서만 작동한다.
그냥 생성자 주입을 쓰는 이유
- DI는 한번 설계되면 거의 변하지 않는다.
- 수정자 주입(SETTER 주입)을 선택하면 Setter method를 public으로 열어두어야 하는데 보동 필드값은 private으로 설정되고 setter을 통해 주입하긴 하지만 변경을 지양해야 할 메서드를 열어두는 것은 좋은것이 아니다.
- final 키워드를 사용할 수 있다.
- final을 넣어서 무조건적으로 해당 의존성을 요구하도록 할 수 있다.
- 즉 컴파일 단계에서 해당 코드의 에러를 잡을 수 있다.
3. 옵션 처리
스프링 빈이 없어도 동작해야 할 때가 있다. 하지만 Autowired만 사용하면 required 옵션의 기본 값이 TRUE로 되어있어서 주입 대상이 없으면 오류가 발생한다.
예시를 통해 알아보자
- Autowired에 required=false : 자동 주입할 대상이 없으면 수정자 메서드 자체가 x
- Nullerble : 자동 주입할 대상이 없으면 null이 입력됨
- Optional : 자동 주입할 대상이 없으면 Optional.empty가 입력된다.
정리
- 생성자 주입을 선택하자
- 기본적으로 생성자 주입을 선택하되, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션으로 부여하자.
4. 롬복
생성자로 DI를 수행하다보면 반복, 코드 길이가 길어지게 된다 그래서 나오게 된게 롬복이다.
세팅
- lombok 설치 및 설정
- enable annotation processing 설정
- 외부 어노테이션 라이브러리가 컴파일 시 문제없이 작동하도록 설정하기 위해서 어노테이션 프로세싱을 활성화 해주어야 한다.
- build.gradle 설정
해당 코드는
lombok
라이브러리를 사용하기 위한 설정입니다.compileOnly
구성요소에 annotationProcessor
를 추가해서 사용하게 됩니다. annotationProcessor
는 컴파일 시점에 사용되는 어노테이션 프로세서를 의미합니다. 이를 추가해주면 lombok
라이브러리가 제공하는 어노테이션을 사용할 수 있습니다.사용
- Getter, Setter 자동 사용
- @Getter, @Setter 어노테이션을 설정해주면 lombok이 getter과 setter메서들을 자동적으로 설정해 준다.
- 의존성 주입 자동화
- 필드를 final로 설정하고 RequiredArgsConstructor어노테이션을 붙여주면 자동적으로 lombok이 생성자 의존성 주입을 해준다.
5. 자동 의존관계 주입 중 빈이 겹칠때
Autowired 필드 명 매칭
- Autowired는 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가적으로 매핑한다.
- 타입 매칭
- 타입 매칭 결과가 2개이상이면 필드 명으로 빈 이름 매칭
Quilifier 사용
추가로 구분할 수 있는 옵션을 붙여주는 방법이다.
이후 호출할 때에는 이런식으로 호출하고
에러의 경우에는
- @Quilifier 끼리 매칭
- 빈 이름 매칭
- 이후 에러 발생한다.
Quilifier 사용 - 인터페이스를 생성해서 오류를 잡기
- 만약 여기서 오타가 나게 되면 컴파일 시점에 에러가 발생하지 않는다.
- 따라서 어노테이션을 새로 생성해서 에러를 컨트롤 할 수 있다.
Primary 사용
@Primary 를 @Component를 선언해서 Bean을 등록할 때 선언해주면 @Primary가 우선권을 가진다.
6. 모든 빈의 조회가 필요할 때
만약 할인 정책에 대하여 클라이언트가 할인의 종류를 선택할 수 있다고 가정하면, 주문에 있어서 할인 서비스를 선택할 수 있어야 한다. 해당 코드는 다음과 같다.
- 여기서 AutoAppConfig는 컴포넌트 스캔을 수행하는 설정파일이다.
- policy들을 Map에 넣고 get 형식으로 할인정책을 가져오면 된다.
- 정확히 말하면 map의 키에 스프링 빈들의 이름이 들어가고 그 값으로 DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담을 수 있다.
스프링 컨테이너를 생성하면서 스프링 빈 등록하기
- 스프링 컨테이너를 생성하고 클래스 정보를 파라미터로 넘기면서 해당 클래스를 자동으로 스프링 빈으로 등록한다.